#level/hardcore

Object decorators are an advanced technique that can be used to add attributes to Objects dynamically whose values are calculated dynamically (on-the-fly) based on an expression.

warning Warning
This feature is still experimental and may change in the (near) future.


The primary use case is Page Decorations, but it is a powerful mechanism that probably has wider applications. As always, with great power comes great responsibility.

Syntax

Object decorations are specified using Space Config (either in ^SETTINGS or elsewhere):

```space-config
objectDecorators:
- where: '<<filter expression>>'
  attributes:
     <<attributePath>>: '<<value expression>>'
```


note Note
For changes to take effect you may have to reload your client (just refresh the page).


A few things of note:

  • <<filter expression>> is a YAML string-encoded expression using SilverBullet’s Expression Language. Some examples:
    • where: 'tags = "book"' to make this apply to all objects that has book as one of its tags.
  • <<attributePath>> can either be a simple attribute name, or a nested one using the attribute.subAttribute syntax. Some examples:
    • fullName
    • pageDecoration.prefix
  • <<value expression>> like <<expression>> must be a YAML string-encoded expression using the Expression Language, some examples together with the attribute path:
    • alwaysTen: '10' (attaches an attribute named alwaysTen with the numeric value 10 to all objects matching the where clause)
    • alwaysTrue: 'true' (same as alwaysTen but with a boolean value)
    • fullName: 'firstName + " " + lastName' (attaches a fullName attribute that concatenates the firstName and lastName attributes with a space in between)
    • nameLength: 'count(name)' (attaches an attribute nameLength with the string length of name — not particularly useful, but to demonstrate you can call Functions here too).


Rules

A few rules and best practices to keep things civil:

  • It is recommended to always filter based on tag (so by adding e.g. tag = "page" to your where clause) to limit the radius of impact. Otherwise you may accidentally apply new attributes of all your Objects (items, tasks, pages, etc.).
  • Dynamic attributes cannot override already existing attributes. If the object already has an attribute with the same name, this value will be kept as is.
  • For performance reasons, all expressions (both filter and value expressions) need to be synchronously evaluatable.
    • Generally, this means they need to be “simple expressions” that require no expensive calls.
    • Simple expressions include simple things like literals, arithmetic, calling some of the cheap Functions such as today() or string manipulation functions.
    • Expensive calls include any additional database queries, or any function call (custom or otherwise) that are asynchronous. These are not supported.
    • This requirement will be checked at runtime. Watch your server logs and browser’s JavaScript JavaScript console to see these errors.


Example

Let’s say that you use the human tag to track various humans in your space, as follows:

firstName: Steve
lastName: Bee
---
firstName: Stephanie
lastName: Bee


This will get you the following data set:

human select firstName, lastName


However, you would like to dynamically compute an additional attribute for all humans, namely fullName. This can be done as follows with Space Config:

objectDecorators:
- where: 'tag = "human"'
  attributes:
     fullName: 'firstName + " " + lastName'


Which will give you the following:

human select fullName, firstName, lastName


As the French say: Voila!